package util;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import entity.annotation.Id;
import entity.annotation.Manytoone;
import entity.annotation.Onetomany;
import entity.annotation.Table;

public class Basedao2<T> {
	private Class<T> classt;
	private Connection con;
	private String tablename;

	public Basedao2() {
		ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
		classt = (Class<T>) pt.getActualTypeArguments()[0];
		con = DBUtil.getConnnection();

		Table tb = classt.getAnnotation(Table.class);// 编译器将把注释记录在类文件中，但在运行时 VM
														// 不需要保留注释。
		if (tb != null)
			tablename = tb.name();// 注释不为空，直接获取表的名字
		else
			tablename = classt.getSimpleName();// 注释为空，用classt.getsimplename获取表的名字

	}

	public List<T> getall() {
		List<T> list = new ArrayList<>();
		StringBuffer sql = new StringBuffer("select * from ").append(tablename);

		try {
			Statement stm = con.createStatement();
			ResultSet rs = stm.executeQuery(sql.toString());
		
			Field[] fd = classt.getDeclaredFields();// 对象的属性，比如你把你看成对象，身高，体重，就是属性，就是字段
			while (rs.next()) {

				T o = classt.newInstance();// 创建一个新的实体entity

				for (int i = 0; i < fd.length; i++) {
					

					fd[i].setAccessible(true);// 第i个属性设置为可以访问
					Manytoone mte = fd[i].getAnnotation(Manytoone.class);// 获取字段的注释
					Onetomany otm = fd[i].getAnnotation(Onetomany.class);
					Class type = fd[i].getType();// 获取属性的类型（int，string）
					String typename = fd[i].getType().getName();// 获取属性的类型的名字（int，string）
					Object val = null;// val为加入到o中的数据
					if (mte == null&&otm==null)// 字段没有注释
						val = rs.getObject(fd[i].getName());// val赋值为：rs执行的SQL语句中的单个字段的名字的值
					else if (mte != null) {// 字段有注解
						String maptab = mte.mapby();// 用mte.mapby（）获取表的名称
						String sql2 = "select * from " + maptab + " where " + mte.id() + "=" + rs.getObject(mte.fk());// 组合sql语句，表名，主键，外键
						Statement st = con.createStatement();
						ResultSet rs1 = st.executeQuery(sql2);
						rs1.next();// 一条一条的读
						Object ro = type.newInstance();// 获取属性类型后创建相同类型的新实体
						Field[] rfd = type.getDeclaredFields();
						// getDeclaredFields()只能获取自己声明的各种字段，
						// 包括public，protected，private。例如：之前取了学生，再取院系
						// 相当于取出注解下的属性，从而连接到连接到另外一个表
						for (int j = 0; j < rfd.length; j++) {
							rfd[j].setAccessible(true);// 设置可以访问
							Object rval = rs1.getObject(rfd[j].getName());
							// rval赋值为：rs1执行的SQL语句中的单个字段的名字的值，把每个新的属性赋值给rval
							if (rfd[j].getType().getSimpleName().equals("int")) {
								BigDecimal bd = (BigDecimal) rval;
								rval = bd.intValue();// 把BigDecimal的rval转换为int
							}
							rfd[j].set(ro, rval);// 把rval传给ro
						}
						val = ro;
					} 
					if (otm != null) {//有onetomany注释
						String maptab = otm.mapby();
						System.out.println(otm.id());
						
						String sqly = "select * from " + maptab + " where " + otm.fk() + "=" + rs.getObject(otm.id());
						Statement st=con.createStatement();
						ResultSet rsu = st.executeQuery(sqly);
						
						List<Object> stus=new ArrayList<>();
						ParameterizedType pt=(ParameterizedType) fd[i].getGenericType();
						
						Class typ=(Class) pt.getActualTypeArguments()[0];
						while (rsu.next()) {
							Object ro = typ.newInstance();
							Field[] rfd = typ.getDeclaredFields();
							for (int j = 0; j < rfd.length; j++) {
								Object rval=null;
								rfd[j].setAccessible(true);
								if(rfd[j].getAnnotation(Manytoone.class)==null&&rfd[j].getAnnotation(Onetomany.class)==null)
									
								{	
									rval=rsu.getObject(rfd[j].getName());
								}
								if (rfd[j].getType().getSimpleName().equals("int")) {
									BigDecimal bd = (BigDecimal) rval;
									rval = bd.intValue();
								}
								rfd[j].set(ro, rval);
							}
							stus.add(ro);
						}
						val = stus;
					}

					if (typename.equals("int")) {
						if (val == null)
							val = 0;
						else {
							BigDecimal bd = (BigDecimal) val;
							val = bd.intValue();// 把BigDecimal转换为int
						}
					}
					fd[i].set(o, val);// 把val的值设置进入o中
				}
				list.add(o);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return list;

	}

	// insert into tablename values(?,?,?.......)table名为class名
	public void insert(T o) {
		StringBuffer sql = new StringBuffer("insert into ").append(tablename).append("valuse");
		Field fd[] = classt.getDeclaredFields();
		for (Field f : fd) {
			f.setAccessible(true);
			sql.append(",");
		}
		sql.deleteCharAt(sql.lastIndexOf(","));
		sql.append(")");
		try {
			PreparedStatement pstm = con.prepareStatement(sql.toString());
			for (int i = 0; i < fd.length; i++) {
				fd[i].setAccessible(true);
				pstm.setObject(i + 1, fd[i].get(o));
			}
			pstm.executeUpdate();
		} catch (Exception e) {

			e.printStackTrace();
		}
	}

	public void deletedata(T o) {
		int idindex = 0;
		StringBuffer sql = new StringBuffer("delete from ").append(tablename + " ").append("where ");
		Field[] fd = classt.getDeclaredFields();
		for (int i = 0; i < fd.length; i++) {
			fd[i].setAccessible(true);
			Id id = fd[i].getAnnotation(Id.class);
			if (id != null) {
				idindex = i;
			}
		}
		fd[0].setAccessible(true);
		String filedname = fd[idindex].getName();
		sql.append(filedname + "=?");
		System.out.println(sql);
		try {
			PreparedStatement psm = con.prepareStatement(sql.toString());
			psm.setObject(1, fd[idindex].get(o));
			psm.executeUpdate();

		} catch (SQLException e) {

			e.printStackTrace();
		} catch (IllegalArgumentException e) {

			e.printStackTrace();
		} catch (IllegalAccessException e) {

			e.printStackTrace();
		}
	}
	// update student set name='tplink',age=16 where ID=23;

	public void update(T o, String country_id) throws IllegalArgumentException, IllegalAccessException {
		int index = 0;
		StringBuffer sql = new StringBuffer("update ").append(tablename + " ").append(" set ");
		Field[] fd = classt.getDeclaredFields();
		for (int i = 0; i < fd.length; i++) {
			fd[i].setAccessible(true);
			String fieldname = fd[i].getName();
			sql.append(fieldname + "=" + "?" + ",");
		}
		String fieldname = fd[0].getName();
		sql.deleteCharAt(sql.lastIndexOf(","));
		sql.append(" where " + fd[0].getName() + "='" + fd[0].get(o) + "'");// 获取第一个成员值
		// System.out.println(sql);
		try {
			PreparedStatement ptsm = con.prepareStatement(sql.toString());
			ptsm.setObject(1, country_id);// 把第一个问号替代为参数值
			for (int i = 1; i < fd.length; i++) {
				ptsm.setObject(i + 1, fd[i].get(o));// i+1表示问号的位置，替代的参数为fd[i].get(o)

			}
			ptsm.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

	}

}
